Automated Presentation of directory src/exampleCode/smoke/

HUB | Up | Download | Pheedbak | Tree | Topic | A-Z | Search | Hot | New


Please be aware: what appears below are the v4.2 DT bits in auto-generated html form.
As we have the time, we will update these to reflect the current "state of the world".


README file from "smoke" directory

  
                ~4Dgifts/toolbox/src/exampleCode/smoke README

            Texture Mapped `smoke' special effects implementation



     to see the demo (with decent results), run the "smoke.sh" script.
     smokeNoTex is an executable built showing plain polygons (see Makefile).
 


   the rest of this file is the text portions of the Smoke.sc showcase file:
   -------------------------------------------------------------------------


    This program started out as a enhancement-request from General Dynamics 
    to Deneb Robotics, for Deneb's factory-floor simulation products.

    There were two parts to the request: 

	1.  a visualization of the source smoke or plume.

	2.  visualizing a compartment filling with smoke according to 
	    some rudimentary CFD calculations.

    I only focused on step 1, with a pointer to the `pfuSmoke' functionality
    inside our Performer product.

    Unfortunately, there were just too many technical hurdles to allow us 
    (myself and the lead gfx programmer at Deneb) to utilize the Performer 
    functionality directly.

    So, I took matters into my own hands and peeked in the source...






    The Performer utility code I looked at had:


    1) an algorithm for translating single quad polygons along a direction 
       vector over time while scaling the quad, and decreasing opacity 
       (increasing transparency?)...


void drawSmoke(uSmoke *smoke, uVec3 eye)
{
    double      now = uGetTime();
    double      deltaTime, age = 1.0f;
...
/* Compute time elapsed from previous uDrawSmoke */
    if(smoke->prevTime < 0.0f)
        deltaTime = 0.0f;
    else
        deltaTime = now - smoke->prevTime;

    if(smoke->duration > 0.0f)
    {
        age = 1.0 - (now - smoke->startTime) / smoke->duration;
...
    }
...
    puffInterval = smoke->puffInterval / age;
    puffDiss = smoke->dissipation/smoke->density * age; 

    puff->t = (now - puff->startTime) / puffDiss;

...
    puff->transp = puff->t * puff->t * puff->t * puff->t;
      
/* Radius is linear interpolation between radius and expansion */
    puff->radius = (1.0f - puff->transp) * smoke->radius +
    puff->transp * smoke->expansion * smoke->radius
...
/* Translate puff based on velocity vector */
    tmp = puff->origin;
    uAddVec3(tmp, tmp, dist);
...

    if(smoke->tex) {
        uApplyTex(smoke->tex);
    }


    drawPuff(puff, smoke, eye);
}


void uApplyTex(uTexture *tex)
{
    if(tex == NULL)
    {
        fprintf(stderr,"uApplyTex() Null uTexture.\n");
        return;
    }
    texbind(TX_TEXTURE_0, tex->index);
}






    2) code to cause all the quads to be rotated to face the eye-point in 
       world coordinate space...


void drawPuff(uPuff *puff, uSmoke *smoke, uVec3 eye)
{
...
 /*
  * Compute matrix which rotates puff to face the eyepoint
  */
  uSubVec3(toEye, eye, puff->origin);

  uMakeRotOntoMat(mat, vec, toEye);

  for(i=0; i<4; i++)
  {
     uVec3           svert;

   /* Scale quad to current radius */
     uScaleVec3(svert, puff->radius, quad[i]);

   /* Offset puff based on radius */
     svert[1] -= smoke->radius;

   /* Rotate puff to follow viewer */
     uXformPt3(dquad[i], svert, mat);

   /* Translate puff to origin */
     uAddVec3(dquad[i], dquad[i], puff->origin);

  }
...
}

***I know this part can and should be done by our hardware;  I just haven't
   had time to finish the change.






    3) a texture map with alpha-channel that would be modulated with the 
       alpha value of the quad.


void drawPuff(uPuff *puff, uSmoke *smoke, uVec3 eye)
{
    uVec4       opaque;
    long        i;
...
#define Zv 0.0
static float t2[]={1,0,Zv,1,1,Zv,0,1,Zv,0,0,Zv};
...
uAddScaledVec3(opaque, smoke->bgnColor, puff->t, smoke->deltaColor);

opaque[3] = 1.0f - puff->transp;

...
#if NOTEXTURE
        #define T2F(t)
#else
        #define T2F(t)  t2f((t))
#endif

/*Draw a puff...finally*/
    lmcolor(LMC_DIFFUSE);
    c4f(opaque);
    bgnpolygon();
        cross(dquad[0],dquad[1],dquad[2],&norm[0],&norm[1],&norm[2]);
        norm_d[0]=(dquad[0][0]-norm[0]);
        norm_d[1]=(dquad[0][1]-norm[1]);
        norm_d[2]=(dquad[0][2]-norm[2]);
        n3f(norm);
        T2F(t2);
        v3f(dquad[0]);
        T2F(t2+3);
        v3f(dquad[1]);
        T2F(t2+6);
        v3f(dquad[2]);
        T2F(t2+9);
        v3f(dquad[3]);
    endpolygon();

#if NOTEXTURE
    bgnline();
       v3f(dquad[0]);
       v3f(norm_d);
    endline();
#endif
}






    There were two stumbling blocks for me, using the smoke utility: 

    1) finding out how to properly setup the texture mapping properties 
       and the texture environment.

    So, with a little help from some 4Dgifts code that worked...


/*
 * Parameters for texturing.
 */
 float texps[] =
  {  TX_MAGFILTER, TX_BILINEAR,
     TX_MINFILTER, TX_MIPMAP_BILINEAR,
     TX_WRAP_S, TX_CLAMP,
     TX_WRAP_T, TX_CLAMP,
     TX_NULL
  };

 float tevps[] = {TV_MODULATE,TV_NULL};


    2) Determining what values to use for afunction(), blendfunc(), and 
       zwritemask():

    Thanks to the Performer source tree, i was able to construct the 
    following:
   
void uDrawSmokes(uVec3 eye)
{
    long        i, n;


    zwritemask(0x00000000);
    if (UGET_GFX_TYPE() & PFGFX_HPC_40NS)   /*express gfx*/
       afunction(0,AF_NOTEQUAL);
    else
       afunction(40,AF_GREATER);

    blendfunction(BF_SA, BF_MSA);

    n = smokeCount;
    for(i=0; i<n; i++) {
        if(smokeList[i]->mode != USMOKE_STOP) {
            drawSmoke(smokeList[i], eye);
        }
    }

    blendfunction(BF_ONE, BF_ZERO);
    zwritemask(0xffffffff);

}






    Creating the textures for stand-alone 'smoke' was alot easier than 
    trying to do it through the full-blown performer interface:

    in uTex.c...

long uLoadTexFile(uTexture *tex, char *name)
{
    IMAGE          *image_in;
    char            path[_MAXSTRING];
    long            ret;

    if(tex == NULL)
    {
        fprintf(stderr,"uLoadTexFile() Null uTexture.\n");
        return -1;
    }
    if(!uFindFile(name, path, R_OK))
    {
      fprintf(stderr,"uLoadTexFile: could not find image file %s\n",name);
      return FALSE;
    }
    if ((image_in = iopen(path, "r")) == NULL)
    {
      fprintf(stderr,"uLoadTexFile: could not load image %s\n", name);
      return FALSE;
    }

    ret = uBuildTex(tex, name, image_in);

    iclose(image_in);
    return ret;
}

in main.c...
void add_fire_tex(void)
{
    fireTex = uNewTex();
    uLoadTexFile(fireTex, "fire.texture.rgb");

    texdef2d(fireTex->index,fireTex->comp,fireTex->sx,fireTex->sy,
             (unsigned long *)fireTex->image,0,texps);
}

void inittex(void)
{
    smokeTex = uNewTex();
    uLoadTexFile(smokeTex, "smoke.texture.rgb");

    texdef2d(smokeTex->index,smokeTex->comp,smokeTex->sx,smokeTex->sy,
             (unsigned long *)smokeTex->image,0,texps);

    add_fire_tex();

    tevdef(1,2,tevps);
    tevbind(0,1);
}







Files of interest from "src/exampleCode/smoke" directory

Source

Documentation

Images

Reference


Select any combo of files you'd like to send yourself a compressed tar image of. Executables/scripts are indicated with a trailing `*' character. (Depending upon the browser, it may be necessary to hold down the Ctrl key to select/deselect disjoint items.) a compressed tar image of the above-selected items.
OR, ...
a compressed tar image of the entire smoke directory.

Copyright © 1995, Silicon Graphics, Inc.